#pragma once
#include <poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "Log.hpp"
#include <memory>
#include "Socket.hpp"
#include "Epoller.hpp"

static const uint16_t defaultport = 8888;
static const int num = 64;
int defaultfd = -1;
int non_event = 0;
uint32_t EVENT_IN = (EPOLLIN);
uint32_t EVENT_OUT = (EPOLLOUT);

class EpollServer
{
public:
    EpollServer(uint16_t port = defaultport)
        : port_(port)
        ,_listensock_ptr(new(Sock))
        , _epoller_ptr(new(Epoller))
    {
    }
    ~EpollServer()
    {
       _listensock_ptr->Close();
    }
    
    void Init()
    {
        _listensock_ptr->Socket();
        _listensock_ptr->Bind(port_);
        _listensock_ptr->Listen();
    }
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport = 0;
        int sockfd = _listensock_ptr->Accept(&clientip, &clientport);
        if (sockfd < 0)
        {
            return;
        }
        lg(Info, "accept success, %s: %d, sock fd: %d", clientip.c_str(), clientport, sockfd);

        _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD,sockfd,EPOLLIN);
       
    }
    void Recver(int fd)
    {
        char buffer[1024];
        ssize_t n=read(fd,buffer,sizeof(buffer)-1);//有bug，这里不能保证是读完整的
        if(n>0)
        {
            buffer[n] = 0;
            std::cout << "get a messge: " << buffer << std::endl;
             // wrirte
            std::string echo_str = "server echo $ ";
            echo_str += buffer;
            write(fd, echo_str.c_str(), echo_str.size());
        }
        else if(n==0)
        {
            lg(Info, "client quit, me too, close fd is : %d", fd);
            //细节3
            _epoller_ptr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);
            close(fd);
        }
        else
        {
            lg(Warning, "recv error: fd is : %d", fd);
             _epoller_ptr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);
            close(fd);
        }
    }
    void Dispatcher(struct epoll_event revs[],int n)
    {
        for(int i=0;i<n;i++)
        {
            uint32_t event=revs[i].events;
            int fd=revs[i].data.fd;
            if(event&EPOLLIN)
            {
                if(fd== _listensock_ptr->Fd())
                {
                     Accepter();
                }
                else{
                    // 其他fd上面的普通读取事件就绪
                    Recver(fd);
                }
            }
            else if (event& EVENT_OUT)
            {
            }
            else
            {
            }
        }
        
    }
    
    void Start()
    {
        int listen_fd = _listensock_ptr->Fd();
        // 将listensock添加到epoll中 -> listensock和他关心的事件，添加到内核epoll模型中rb_tree.
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD,listen_fd, EVENT_IN);

        struct epoll_event revs[num];
        for(;;)
        {
            int n= _epoller_ptr->EpollerWait(revs,num);
            if (n > 0)
            {
                // 有事件就绪
                lg(Debug, "event happened, fd is : %d", revs[0].data.fd);
                Dispatcher(revs, n);
            }
            else if (n == 0)
            {
                lg(Info, "time out ...");
            }
            else
            {
                lg(Error, "epll wait error");
            }
        }
    }

private:
    uint16_t port_;
    std::shared_ptr<Sock> _listensock_ptr;
     std::shared_ptr<Epoller> _epoller_ptr;
};